<template>
  <div class="container">
    <!-- <el-tabs v-model="activeTab" class="tabs" @tab-click="handleTabClick">
      <el-tab-pane label="酸轧TCM2280" name="tcm2280" />
      <el-tab-pane label="连退CAL2150" name="cal2150" />
      <el-tab-pane label="连退CAL1630" name="cal1630" />
      <el-tab-pane label="镀锌CGL1870" name="cgl1870" />
    </el-tabs> -->
    <el-container>
      <el-header style="height: 15vh">
        <el-form :model="searchHeader" label-width="auto" class="header-search-form">
          <div class="form-group">
            <el-form-item>
              <el-dropdown @command="handleCommand">
                <span class="el-dropdown-link">
                  {{ curLine }}<el-icon class="el-icon--right"><arrow-down /></el-icon>
                </span>
                <template #dropdown>
                  <el-dropdown-menu>
                    <el-dropdown-item command="tcm2280">酸轧2280</el-dropdown-item>
                    <el-dropdown-item command="cal1630">连退1630</el-dropdown-item>
                    <el-dropdown-item command="cal2150">连退2150</el-dropdown-item>
                    <el-dropdown-item command="cgl1870">镀锌1870</el-dropdown-item>
                  </el-dropdown-menu>
                </template>
              </el-dropdown>
            </el-form-item>
            <el-form-item label="开始时间" class="time-period-picker">
              <el-date-picker
                v-model="searchHeader.startDate"
                type="datetime"
                placeholder="开始时间"
                value-format="YYYY-MM-DD HH:mm:ss"
                style="min-width: 160px"
              />
            </el-form-item>
            <el-form-item label="结束时间" class="time-period-picker">
              <el-date-picker
                v-model="searchHeader.endDate"
                type="datetime"
                placeholder="结束时间"
                value-format="YYYY-MM-DD HH:mm:ss"
                style="min-width: 160px"
              />
            </el-form-item>
            <el-form-item label="钢种">
              <el-input v-model="searchHeader.steelGrade" placeholder="请输入钢种" style="max-width: 12rem" />
            </el-form-item>
            <alarm-message :message="warningMessage" />
          </div>
          <div class="form-group">
            <el-form-item label="原料厚度">
              <el-input v-model="searchHeader.entThickStart" style="max-width: 8rem" />
              <span class="space">-</span>
              <el-input v-model="searchHeader.entThickEnd" style="max-width: 10rem" />
            </el-form-item>
            <el-form-item label="原料宽度">
              <el-input v-model="searchHeader.entWidthStart" style="max-width: 10rem" />
              <span class="space">-</span>
              <el-input v-model="searchHeader.entWidthEnd" style="max-width: 10rem" />
            </el-form-item>
            <el-form-item label="出口厚度">
              <el-input v-model="searchHeader.extThickStart" style="max-width: 10rem" />
              <span class="space">-</span>
              <el-input v-model="searchHeader.extThickEnd" style="max-width: 10rem" />
            </el-form-item>
            <el-form-item label="出口宽度">
              <el-input v-model="searchHeader.extWidthStart" style="max-width: 10rem" />
              <span class="space">-</span>
              <el-input v-model="searchHeader.extWidthEnd" style="max-width: 10rem" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="handleQuery">查询</el-button>
              <el-button type="primary" @click="handleReset">重置</el-button>
            </el-form-item>
          </div>
        </el-form>
      </el-header>
      <el-container>
        <el-aside width="20%" class="coild-list">
          <el-card>
            <template #header>
              <div class="card-header">
                <span>带钢基本信息</span>
              </div>
            </template>
            <!-- 
              element-loading-spinner="el-icon-loading" -->
            <el-table
              :data="coildList"
              max-height="70vh"
              class="data-table"
              :header-cell-style="{ background: '#2f59af', color: '#fff', textAlign: 'center' }"
              :cell-style="{ color: '#fff', textAlign: 'center' }"
              v-loading="isLoading"
              element-loading-text="加载中..."
              element-loading-background="transparent"
              @row-click="coildListClick"
              ref="tableRef"
            >
              <el-table-column prop="serialNumber" label="序号" width="80" />
              <el-table-column prop="dialNumber" label="卷号" />
              <template #empty>
                <div style="color: #fff; text-align: center; padding: 20px" v-if="!isLoading">暂无数据</div>
              </template>
            </el-table>
          </el-card>
        </el-aside>
        <el-main class="charts-container" v-loading="isLoading" element-loading-text="图表加载中..." element-loading-background="transparent">
          <div class="charts-grid" v-if="hasChartData">
            <div
              class="chart-item"
              v-for="index in chartCount"
              :key="index"
              :ref="
                (el) => {
                  if (el && chartRefs[index - 1]) {
                    chartRefs[index - 1].value = el as HTMLElement;
                  }
                }
              "
            ></div>
          </div>
          <div v-else class="no-charts">
            <div style="color: #fff; text-align: center; padding: 40px">暂无图表数据</div>
          </div>
        </el-main>
      </el-container>
    </el-container>
  </div>

  <el-dialog v-model="dialogVisible" :title="dialogTitle" width="90%" class="dialog" :destroy-on-close="true" @close="close">
    <pcrc-chart :coild-no="clickCoildNo" :production-line="activeTab" />
  </el-dialog>
</template>
<script setup lang="ts">
  import { ref, reactive, onMounted, onUnmounted, nextTick, shallowRef, computed } from 'vue';
  import { ElMessage, ElNotification } from 'element-plus';
  import pcrcChart from './components/PPCRChart.vue';
  import type { TabsPaneContext, ElTable } from 'element-plus';
  import { rateApi } from '/@/api/report/processParameter/index';
  import * as echarts from 'echarts/core';
  import AlarmMessage from './components/AlarmMessage/AlarmMessage.vue';
  import { debounce } from 'lodash-es';
  import dayjs from 'dayjs';
  import { ArrowDown } from '@element-plus/icons-vue';

  const tabTextMap: Record<string, string> = {
    tcm2280: '酸轧2280',
    cal1630: '连退1630',
    cal2150: '连退2150',
    cgl1870: '镀锌1870',
  };

  type ActiveTabKey = keyof typeof tabTextMap | string;
  const activeTab = ref<'tcm2280' | 'cal1630' | 'cal2150' | 'cgl1870'>('tcm2280');
  const curLine = computed(() => {
    return tabTextMap[activeTab.value as ActiveTabKey] ?? '酸轧2280';
  });
  const handleCommand = (command: 'tcm2280' | 'cal1630' | 'cal2150' | 'cgl1870') => {
    activeTab.value = command;
    searchHeader.prodLine = command;
    handleReset();
  };

  const errList = ref<any[]>([]);
  // const activeTab = ref('tcm2280');
  const dialogVisible = ref(false);
  const dialogTitle = ref('');
  const clickCoildNo = ref('');
  const coildList = ref<InstanceType<typeof ElTable> | []>([]);
  const isLoading = ref(false);

  interface SearchHeader {
    prodLine: string;
    startDate: string;
    endDate: string;
    steelGrade: string;
    entThickStart: string;
    entThickEnd: string;
    entWidthStart: string;
    entWidthEnd: string;
    extThickStart: string;
    extThickEnd: string;
    extWidthStart: string;
    extWidthEnd: string;
  }

  // 搜索头
  const searchHeader = reactive<SearchHeader>({
    prodLine: activeTab.value,
    startDate: '',
    endDate: '',
    steelGrade: '',
    entThickStart: '',
    entThickEnd: '',
    entWidthStart: '',
    entWidthEnd: '',
    extThickStart: '',
    extThickEnd: '',
    extWidthStart: '',
    extWidthEnd: '',
  });

  // 产线数据
  interface LineData {
    graphNames: string[];
    graphKeys: string[];
    limitKeys: string[];
  }
  const currLineData = ref<LineData>({
    graphNames: [],
    graphKeys: [],
    limitKeys: [],
  });
  const tcm2280Data = ref<LineData>({
    graphNames: [
      '工艺段速度',
      '1#酸槽温度',
      '2#酸槽温度',
      '3#酸槽温度',
      '1#游离酸浓度',
      '1#铁离子浓度',
      '3#游离酸浓度',
      '3#铁离子浓度',
      '漂洗槽PH值',
      '烘干机温度',
      '轧制速度',
      '乳化液1#箱温度',
      '乳化液2#箱温度',
      '乳化液3#箱温度',
      '铁含量',
      '杂油含量',
      '1#乳化液喷射梁压力',
      '2#乳化液喷射梁压力',
      '3#乳化液喷射梁压力',
      '4#乳化液喷射梁压力',
      '5#乳化液喷射梁压力',
      '带钢表面反射率',
    ],
    graphKeys: [
      'tcmProcessSpeedArr',
      'tcmTank1TempArr',
      'tcmTank2TempArr',
      'tcmTank3TempArr',
      'acid1',
      'feContent1',
      'acid3',
      'feContent3',
      'tcmRinsePhArr',
      'tcmDryTempArr',
      'rollSpeedArr',
      'tcmTank1EmuTempArr',
      'tcmTank2EmuTempArr',
      'tcmTank3EmuTempArr',
      'feContent',
      'impureOil',
      'tcm1RuPressureArr',
      'tcm2RuPressureArr',
      'tcm3RuPressureArr',
      'tcm4RuPressureArr',
      'tcm5RuPressureArr',
      'bandFslv',
    ],
    limitKeys: [
      // 这里需要根据实际需求添加TCM2280产线的限制键名
      // 暂时留空，等待具体需求
    ],
  });
  const cal1630Data = ref<LineData>({
    graphNames: [
      '工艺段速度均值[m/min]',
      '粗糙度检测仪均值',
      '加热段带温均值',
      '缓冷段带温均值',
      '快冷段带温均值',
      '时效3段带温均值',
      '平整延伸率实际值均值[%]',
      '#1碱浸刷洗槽循环槽碱液电导率平均值',
      '#2碱浸刷洗槽循环槽碱液电导率平均值',
      '#1碱浸刷洗槽循环槽碱液温度平均值',
      '#2碱浸刷洗槽循环槽碱液温度平均值',
      '电解清洗循环槽碱液电导率平均值',
      '电解清洗循环槽碱液温度平均值',
      '热水漂洗循环槽温度',
      '快冷Z1-2段氢含量',
      'Htg1氢含量',
      'Htg1炉压',
      '水淬槽水温',
      '水淬槽电导率',
    ],
    graphKeys: [
      'calProcessSpeedArr',
      'calSpmRaArr',
      'calHeatStripTempArr',
      'calScStripTempArr',
      'calRcStripTempArr',
      'calOas3StripTempArr',
      'calSpmElongActArr',
      'calAlkali1WashCondArr',
      'calAlkali2WashCondArr',
      'calAlkali1WashTempArr',
      'calAlkali2WashTempArr',
      'calElecCleanCondArr',
      'calElecCleanTempArr',
      'calHotWaterRinseTempArr',
      'calRcZ12H2Arr',
      'calHeatH2Arr',
      'calHeatFurPressureArr',
      'calQuenchTempArr',
      'calQuenchCondArr',
    ],
    limitKeys: [],
  });
  const cal2150Data = ref<LineData>({
    graphNames: [
      '工艺段速度均值[m/min]',
      '粗糙度检测仪均值',
      '加热段带温均值',
      '缓冷段带温均值',
      '快冷段带温均值',
      '时效3段带温均值',
      '平整延伸率实际值均值[%]',
      '#1碱浸刷洗槽循环槽碱液电导率平均值',
      '#2碱浸刷洗槽循环槽碱液电导率平均值',
      '#1碱浸刷洗槽循环槽碱液温度平均值',
      '#2碱浸刷洗槽循环槽碱液温度平均值',
      '电解清洗循环槽碱液电导率平均值',
      '电解清洗循环槽碱液温度平均值',
      '热水漂洗循环槽温度',
      '快冷Z1-2段氢含量',
      'Htg1氢含量',
      'Htg1炉压',
      '水淬槽水温',
      '水淬槽电导率',
    ],
    graphKeys: [
      'calProcessSpeedArr',
      'calSpmRaArr',
      'calHeatStripTempArr',
      'calScStripTempArr',
      'calRcStripTempArr',
      'calOas3StripTempArr',
      'calSpmElongActArr',
      'calAlkali1WashCondArr',
      'calAlkali2WashCondArr',
      'calAlkali1WashTempArr',
      'calAlkali2WashTempArr',
      'calElecCleanCondArr',
      'calElecCleanTempArr',
      'calHotWaterRinseTempArr',
      'calRcZ12H2Arr',
      'calHeatH2Arr',
      'calHeatFurPressureArr',
      'calQuenchTempArr',
      'calQuenchCondArr',
    ],
    limitKeys: [],
  });
  const cgl1870Data = ref<LineData>({
    graphNames: [
      '碱喷电导率实际[μS/cm]',
      '碱刷电导率实际[μS/cm]',
      '清洗段碱喷循环槽温度[℃]',
      '清洗段碱刷循环槽温度[℃]',
      '清洗段电解循环槽温度[℃]',
      '清洗段漂洗循环槽温度[℃]',
      '电解电导率实际[μS/cm]',
      '漂洗电导率实际[μS/cm]',
      '光整液浓度',
      '气刀距离实际值-上表面',
      '气刀距离实际值-下表面',
      '气刀高度实际值-上表面',
      '气刀高度实际值-下表面',
      'GI锌锅温度',
      // 'GA锌锅温度',
      '延伸率实际（spm el）',
    ],
    graphKeys: [
      'sprayCondActArr',
      'brushCondActArr',
      'sprayTempArr',
      'brushTempArr',
      'elecTempArr',
      'rinseTempArr',
      'elecCondActArr',
      'rinseCondActArr',
      'spmLiquidConcArr',
      'airKnifeDisTopArr',
      'airKnifeDisBtmArr',
      'airKnifeHighTopArr',
      'airKnifeHighBtmArr',
      'giZnpotTempArr',
      // 'gaZnpotTempArr',
      'spmElongActArr',
    ],
    limitKeys: [
      'sprayCondActA',
      'sprayCondActB',
      'brushCondActA',
      'brushCondActB',
      'sprayTempA',
      'sprayTempB',
      'brushTempA',
      'brushTempB',
      'elecTempA',
      'elecTempB',
      'rinseTempA',
      'rinseTempB',
      'elecCondActA',
      'elecCondActB',
      'rinseCondActA',
      'rinseCondActB',
      'spmLiquidConcA',
      'spmLiquidConcB',
      'airKnifeDisTopA',
      'airKnifeDisTopB',
      'airKnifeDisBtmA',
      'airKnifeDisBtmB',
      'airKnifeHighTopA',
      'airKnifeHighTopB',
      'airKnifeHighBtmA',
      'airKnifeHighBtmB',
      'giZnpotTempA',
      'giZnpotTempB',
      // 'gaZnpotTempA',
      // 'gaZnpotTempB',
      'spmElongActA',
      'spmElongActB',
    ],
  });

  // 数据缓存
  const dataCache = new Map<string, any>();
  const CACHE_DURATION = 5 * 60 * 1000; // 5分钟缓存

  // 防抖查询函数
  const debouncedFetchData = debounce(async () => {
    if (isLoading.value) return;
    await fetchData();
  }, 300);

  // 切换产线
  // const handleTabClick = (tab: TabsPaneContext) => {
  //   const name = String(tab.paneName ?? '');
  //   activeTab.value = name;
  //   searchHeader.prodLine = name;
  //   handleReset();
  //   // getCurLineData(name);
  //   // debouncedFetchData();
  // };

  // 查询按钮
  const handleQuery = () => {
    getCurLineData(activeTab.value);
    debouncedFetchData();
  };

  // 重置方法
  const handleReset = () => {
    (Object.keys(searchHeader) as Array<keyof SearchHeader>).forEach((key) => {
      searchHeader[key] = '';
    });
    searchHeader.prodLine = activeTab.value;
    initSearchTime();
    handleQuery();
  };

  const coildListClick = (row: any) => {
    dialogVisible.value = true;
    clickCoildNo.value = row.dialNumber;
  };

  // 卷号图标dialog关闭
  const close = () => {
    dialogVisible.value = false;
  };

  // ---------------------------------------------- 数据对接 -------------------------------------------

  const fetchCoildList = async () => {
    try {
      const param = { ...searchHeader };
      const cacheKey = `coildList_${JSON.stringify(param)}`;

      // 检查缓存
      const cached = dataCache.get(cacheKey);
      if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
        coildList.value = cached.data;
        return;
      }

      const res = await rateApi.techList(param);
      if (res && res.data && res.data.data && Array.isArray(res.data.data)) {
        const data = res.data.data.map((item: any) => ({
          serialNumber: item.seqno,
          dialNumber: item.volumeNo,
        }));
        coildList.value = data;

        // 缓存数据
        dataCache.set(cacheKey, {
          data,
          timestamp: Date.now(),
        });
      } else {
        coildList.value = [];
        throw new Error('返回值不存在或返回值格式有误');
      }
    } catch (err: any) {
      const errorInfo = {
        message: '获取卷号数据失败',
        error: err instanceof Error ? err.message : String(err),
        timestamp: new Date().toISOString(),
      };
      console.error('API Error:', errorInfo);
      errList.value.push(errorInfo.message);
    }
  };

  const fetchGraphData = async () => {
    try {
      const param = { ...searchHeader };
      const cacheKey = `graphData_${JSON.stringify(param)}`;

      // 检查缓存
      const cached = dataCache.get(cacheKey);
      if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
        Object.assign(graphData, cached.graphData);
        Object.assign(limitData, cached.limitData);
        return;
      }

      const res = await rateApi.techFit(param);
      if (res && res.data && res.data.data) {
        const data = res.data.data;
        const newGraphData: Record<string, any[]> = {};
        const newLimitData: Record<string, any> = {};

        currLineData.value.graphKeys.forEach((key) => {
          if (data[key]) {
            newGraphData[key] = data[key];
          }
        });
        currLineData.value.limitKeys.forEach((key) => {
          if (data[key]) {
            newLimitData[key] = data[key];
          }
        });

        Object.assign(graphData, newGraphData);
        Object.assign(limitData, newLimitData);

        // 缓存数据
        dataCache.set(cacheKey, {
          graphData: newGraphData,
          limitData: newLimitData,
          timestamp: Date.now(),
        });
      } else {
        throw new Error('返回值不存在或返回值格式有误');
      }
    } catch (err: any) {
      const errorInfo = {
        message: '获取图表数据失败',
        error: err instanceof Error ? err.message : String(err),
        timestamp: new Date().toISOString(),
      };
      console.error('API Error:', errorInfo);
      errList.value.push(errorInfo.message);
    }
  };

  const fetchData = async () => {
    if (isLoading.value) return;

    isLoading.value = true;
    errList.value = []; // 清空错误列表

    try {
      await Promise.all([fetchCoildList(), fetchGraphData(), getWarningMessage()]);
      await nextTick();
      await initCharts();

      if (errList.value.length > 0) {
        ElNotification({
          title: 'Error',
          message: errList.value.join('<br>'),
          type: 'error',
          dangerouslyUseHTMLString: true,
        });
      } else {
        ElMessage.success('查询成功');
      }
    } catch (error) {
      console.error('数据获取失败:', error);
      ElMessage.error('数据获取失败');
    } finally {
      isLoading.value = false;
    }
  };

  // 窗口大小变化时自适应重绘图表
  const handleResize = () => {
    chartInstances.value.forEach((chart) => {
      if (chart) chart.resize();
    });
  };

  // 防抖的resize处理函数
  const debouncedHandleResize = debounce(handleResize, 100);

  function initSearchTime() {
    searchHeader.startDate = dayjs().format('YYYY-MM-DD 00:00:00');
    searchHeader.endDate = dayjs().format('YYYY-MM-DD HH:mm:ss');
  }

  onMounted(() => {
    initSearchTime();
    getCurLineData('tcm2280');
    fetchData();

    // 添加窗口大小变化监听
    window.addEventListener('resize', debouncedHandleResize);

    // 安排整点刷新提示信息
    scheduleHourlyWarningRefresh();
  });

  onUnmounted(() => {
    // 移除窗口大小变化监听
    window.removeEventListener('resize', debouncedHandleResize);

    // 清理所有图表实例
    chartInstances.value.forEach((chart) => {
      if (chart) {
        chart.dispose();
      }
    });

    // 清空引用
    chartInstances.value = [];
    chartRefs.value = [];

    // 清理数据缓存
    dataCache.clear();

    // 清理错误列表
    errList.value = [];

    // 清理整点刷新定时器
    if (warningAlignTimeout) clearTimeout(warningAlignTimeout);
    if (warningHourlyTimer) clearInterval(warningHourlyTimer);
  });

  // ------------------------------------------------------------- 图表区域  --------------------------------------------

  const curUpperLimit = ref(0);
  const curLowerLimit = ref(0);

  const option = {
    title: {
      left: 'center',
      textStyle: {
        fontSize: 16,
        fontWeight: 'bolder',
        color: '#fff', // 主标题文字颜色
      },
      text: '散点图', // 主标题文字内容
    },
    grid: {
      left: 10,
      right: 30,
      top: 20,
      bottom: 10,
      containLabel: true,
    },
    // 提示框
    tooltip: {
      // appendToBody: true, // 关键设置
      trigger: 'item', // 触发类型，默认数据触发，见下图，可选为：'item' ¦ 'axis'
      showDelay: 20, // 显示延迟，添加显示延迟可以避免频繁切换，单位ms
      hideDelay: 300, // 隐藏延迟，单位ms
      transitionDuration: 0.3, // 动画变换时间，单位s
      // 接受数组分别设定上右下左边距，同css
      axisPointer: {
        // 坐标轴指示器，坐标轴触发有效
        type: 'line', // 默认为直线，可选为：'line' | 'shadow'
        lineStyle: {
          // 直线指示器样式设置
          color: '#48b',
          width: 1,
          type: 'solid',
        },
        // axisPointer: {
        //   type: 'shadow',
        // },
        shadowStyle: {
          // 阴影指示器样式设置
          width: 'auto', // 阴影大小
          color: 'rgba(150,150,150,0.3)', // 阴影颜色
        },
      },
      textStyle: {
        color: '#333',
      },
    },
    xAxis: {
      data: [0],
    },
    yAxis: {
      // scale: true,
      splitLine: {
        show: false,
      },
      min: 0,
      max: 0,
    },
    series: [
      {
        type: 'scatter',
        symbolSize: 4,
        large: false,
        data: [0],
        name: '',
        itemStyle: {
          color: function (params: any) {
            // 获取当前数据值
            const value = params.data;

            // 根据值的范围返回不同颜色
            if (curUpperLimit.value && curUpperLimit.value != 0 && curLowerLimit.value && curLowerLimit.value != 0) {
              if (value > curUpperLimit.value || value < curLowerLimit.value) {
                return '#ff4d4f'; // 超过上限，红色
              } else {
                return '#2af598'; // 在正常范围内，绿色
              }
            } else if (curUpperLimit.value && curUpperLimit.value != 0) {
              if (value > curUpperLimit.value) {
                return '#ff4d4f'; // 超过上限，红色
              } else {
                return '#2af598'; // 在正常范围内，绿色
              }
            } else if (curLowerLimit.value && curLowerLimit.value != 0) {
              if (value < curLowerLimit.value) {
                return '#ff4d4f'; // 超过下限，红色
              } else {
                return '#2af598'; // 在正常范围内，绿色
              }
            } else {
              return '#2af598'; // 在正常范围内，绿色
            }
          },
        },
        markLine: {
          symbol: 'none',
          silent: true,
          data: [
            {
              yAxis: 0,
              lineStyle: {
                color: '#fff',
                width: 1,
              },
              label: {
                formatter: '上限',
                color: '#fff',
                position: 'top',
              },
            },
            {
              yAxis: 0,
              lineStyle: {
                color: '#fff',
                width: 1,
              },
              label: {
                formatter: '下限',
                color: '#fff',
                position: 'bottom',
              },
            },
          ],
        },
      },
    ],
  };

  const chartRefs = shallowRef<Ref<HTMLElement | null>[]>([]);
  const chartInstances = shallowRef<(echarts.ECharts | null)[]>([]);

  // 计算属性优化
  const chartCount = computed(() => currLineData.value.graphKeys.length);
  const hasChartData = computed(() => chartCount.value > 0);

  type GraphKey = (typeof currLineData.value.graphKeys)[number];

  const graphData = reactive<Record<GraphKey, any[]>>(
    Object.fromEntries(currLineData.value.graphKeys.map((key) => [key, []])) as Record<GraphKey, any[]>
  );
  const limitData = reactive<Record<string, any>>(Object.fromEntries(currLineData.value.limitKeys.map((key) => [key, ''])) as Record<string, any>);

  const initCharts = async () => {
    // 检查数据完整性
    if (!hasChartData.value) {
      console.warn('当前产线没有配置图表数据');
      return;
    }

    // 使用requestAnimationFrame进行分批渲染，避免阻塞UI
    const renderCharts = async () => {
      const batchSize = 3; // 每批渲染3个图表

      for (let i = 0; i < chartRefs.value.length; i += batchSize) {
        const batch = chartRefs.value.slice(i, i + batchSize);

        await Promise.all(
          batch.map(async (chartRef, batchIndex) => {
            const index = i + batchIndex;
            await initSingleChart(chartRef, index);
          })
        );

        // 每批之间添加小延迟，让UI有机会更新
        if (i + batchSize < chartRefs.value.length) {
          await new Promise((resolve) => setTimeout(resolve, 16)); // 约一帧的时间
        }
      }
    };

    await renderCharts();
  };

  const initSingleChart = async (chartRef: Ref<HTMLElement | null>, index: number) => {
    try {
      if (!chartRef.value || chartInstances.value[index]) return;

      const graphKey = currLineData.value.graphKeys[index];
      const hasLimits = Array.isArray(currLineData.value.limitKeys) && currLineData.value.limitKeys.length > 0;

      // 创建图表配置的深拷贝
      const chartOption = JSON.parse(JSON.stringify(option));

      // 数据
      chartOption.series[0].data = graphData[graphKey] && Array.isArray(graphData[graphKey]) ? graphData[graphKey] : [];

      // 上下限值
      let lowerLimit = 0;
      let upperLimit = 0;

      if (hasLimits) {
        const limitKeyA = currLineData.value.limitKeys[index * 2] || null;
        const limitKeyB = currLineData.value.limitKeys[index * 2 + 1] || null;
        const toNum = (v: any) => (v === '' || v == null ? undefined : Number(v));
        lowerLimit = limitKeyA ? toNum(limitData[limitKeyA]) ?? 0 : 0;
        upperLimit = limitKeyB ? toNum(limitData[limitKeyB]) ?? 0 : 0;
      }

      // y 轴范围
      const { min, max } = findMinMax(chartOption.series[0].data, lowerLimit, upperLimit);
      chartOption.yAxis.min = Number((min * 0.96).toFixed(2));
      chartOption.yAxis.max = Number((max * 1.05).toFixed(2));

      chartOption.title.text = currLineData.value.graphNames[index] || `图表 ${index + 1}`;
      chartOption.series[0].name = currLineData.value.graphNames[index] || `图表 ${index + 1}`;
      chartOption.xAxis.data =
        Array.from({ length: graphData[graphKey] && Array.isArray(graphData[graphKey]) ? graphData[graphKey].length : 0 }, (_, i) => i + 1) ?? [];

      // 上下限线
      chartOption.series[0].markLine.data = [];
      if (hasLimits) {
        const limitKeyA = currLineData.value.limitKeys[index * 2] || null;
        const limitKeyB = currLineData.value.limitKeys[index * 2 + 1] || null;
        const markLineData: any[] = [];
        if (limitKeyA && limitKeyB && limitData[limitKeyA] && limitData[limitKeyB]) {
          markLineData.push(
            {
              yAxis: limitData[limitKeyA],
              lineStyle: { color: '#fff', width: 1 },
              label: { formatter: `下限：${limitData[limitKeyA]}`, color: '#fff', position: 'insideEndBottom' },
            },
            {
              yAxis: limitData[limitKeyB],
              lineStyle: { color: '#fff', width: 1 },
              label: { formatter: `上限：${limitData[limitKeyB]}`, color: '#fff', position: 'insideEndTop' },
            }
          );
        } else if (limitKeyA && limitData[limitKeyA]) {
          markLineData.push({
            yAxis: limitData[limitKeyA],
            lineStyle: { color: '#fff', width: 1 },
            label: { formatter: `下限：${limitData[limitKeyA]}`, color: '#fff', position: 'insideEndBottom' },
          });
        } else if (limitKeyB && limitData[limitKeyB]) {
          markLineData.push({
            yAxis: limitData[limitKeyB],
            lineStyle: { color: '#fff', width: 1 },
            label: { formatter: `上限：${limitData[limitKeyB]}`, color: '#fff', position: 'insideEndTop' },
          });
        }
        chartOption.series[0].markLine.data = markLineData;
      }

      // 更新颜色函数中的上下限值
      chartOption.series[0].itemStyle.color = function (params: any) {
        const value = params.data;
        if (upperLimit && upperLimit != 0 && lowerLimit && lowerLimit != 0) {
          if (value > upperLimit || value < lowerLimit) {
            return '#ff4d4f';
          } else {
            return '#2af598';
          }
        } else if (upperLimit && upperLimit != 0) {
          if (value > upperLimit) {
            return '#ff4d4f';
          } else {
            return '#2af598';
          }
        } else if (lowerLimit && lowerLimit != 0) {
          if (value < lowerLimit) {
            return '#ff4d4f';
          } else {
            return '#2af598';
          }
        } else {
          return '#2af598';
        }
      };

      chartInstances.value[index] = echarts.init(chartRef.value);
      chartInstances.value[index]?.setOption(chartOption, true);

      // 添加散点图点击事件
      chartInstances.value[index]?.on('click', (params) => {
        handleScatterClick(params);
      });
    } catch (error) {
      const chartName = currLineData.value.graphNames[index] || `图表 ${index + 1}`;
      const errorInfo = {
        message: `图表 ${chartName} 初始化失败`,
        error: error instanceof Error ? error.message : String(error),
        timestamp: new Date().toISOString(),
      };
      console.error('API Error:', errorInfo);
      errList.value.push(errorInfo.message);
    }
  };

  function findMinMax(numbers: any[], lower?: number, upper?: number): { min: number; max: number } {
    const valid: number[] = numbers.map((v) => (v === '' ? undefined : v)).filter((v): v is number => typeof v === 'number' && !Number.isNaN(v));

    if (valid.length === 0) {
      const base = lower && typeof lower === 'number' ? lower : 0;
      return { min: base, max: upper && typeof upper === 'number' ? upper : base };
    }

    let min = valid[0],
      max = valid[0];
    for (const num of valid) {
      if (num < min) min = num;
      if (num > max) max = num;
    }

    if (lower && typeof lower === 'number' && lower != 0 && lower < min) min = lower;
    if (lower && typeof lower === 'number' && lower != 0 && lower > max) max = lower;
    if (upper && typeof upper === 'number' && upper != 0 && upper > max) max = upper;
    if (upper && typeof upper === 'number' && upper != 0 && upper < min) min = upper;
    return { min, max };
  }

  // -----------------------------------------  卷号列表滚动相关 ---------------------------------------------
  const tableRef = ref<InstanceType<typeof ElTable> | null>(null);

  /**
   * 处理散点图点击事件
   * @param params 点击事件的参数
   */
  const handleScatterClick = (params: any) => {
    const { dataIndex } = params;

    // 如果需要，可以滚动到对应的卷号
    scrollRowToTop(dataIndex);
  };

  /**
   * 将表格中指定索引的行滚动到第一行位置
   * @param index 要滚动到顶部的行索引
   */
  const scrollRowToTop = (index: number) => {
    // 检查表格引用是否存在
    if (!tableRef.value) return;

    // 等待下一个 tick 确保 DOM 完全渲染
    nextTick(() => {
      // 获取表格DOM元素
      const tableEl = tableRef.value?.$el as HTMLElement;
      if (!tableEl) return;

      // 直接使用正确的滚动容器
      let scrollContainer = tableEl.querySelector('.el-scrollbar__wrap') as HTMLElement;

      // 如果找不到，尝试其他可能的选择器作为备选
      if (!scrollContainer) {
        scrollContainer = tableEl.querySelector('.el-table__body-wrapper') as HTMLElement;
      }

      if (!scrollContainer) {
        scrollContainer = tableEl.querySelector('.el-table__body') as HTMLElement;
      }

      if (!scrollContainer) {
        console.error('找不到滚动容器');
        return;
      }

      // 获取滚动容器的高度值
      const scrollHeight = scrollContainer.scrollHeight;
      const clientHeight = scrollContainer.clientHeight;

      // 检查是否有滚动条
      const hasScrollbar = scrollHeight > clientHeight;

      if (!hasScrollbar) {
        return;
      }

      // 获取所有行元素
      const rows = scrollContainer.querySelectorAll('.el-table__row') as NodeListOf<HTMLElement>;

      // 检查索引是否有效
      if (index < 0 || index >= rows.length) {
        return;
      }

      // 获取目标行
      const targetRow = rows[index];
      if (!targetRow) return;

      // 计算需要滚动的距离
      const scrollTop = targetRow.offsetTop;
      const maxScrollTop = scrollHeight - clientHeight;

      // 执行滚动
      if (scrollTop > maxScrollTop) {
        scrollContainer.scrollTop = maxScrollTop;
      } else {
        scrollContainer.scrollTop = scrollTop;
      }
    });
  };

  // -----------------------------------------------------------  获取当前产线数据 -------------------------------------------

  const getCurLineData = (tabName: string) => {
    if (tabName === 'cgl1870') {
      currLineData.value = cgl1870Data.value;
    } else if (tabName === 'tcm2280') {
      currLineData.value = tcm2280Data.value;
    } else if (tabName === 'cal1630') {
      currLineData.value = cal1630Data.value;
    } else if (tabName === 'cal2150') {
      currLineData.value = cal2150Data.value;
    }

    // 重新初始化图表引用数组
    initChartRefs();
  };

  const initChartRefs = () => {
    // 清理旧的图表实例
    chartInstances.value.forEach((chart) => {
      if (chart) {
        chart.dispose();
      }
    });

    // 重新创建图表引用数组
    chartRefs.value = Array.from({ length: currLineData.value.graphKeys.length }, () => ref<HTMLElement | null>(null));
    chartInstances.value = Array.from({ length: currLineData.value.graphKeys.length }, () => null);

    // 重新初始化 graphData 和 limitData
    initGraphData();
  };

  const initGraphData = () => {
    // 清空现有的 graphData
    Object.keys(graphData).forEach((key) => {
      delete graphData[key];
    });

    // 重新初始化 graphData
    currLineData.value.graphKeys.forEach((key) => {
      graphData[key] = [];
    });

    // 清空现有的 limitData
    Object.keys(limitData).forEach((key) => {
      delete limitData[key];
    });

    // 重新初始化 limitData
    currLineData.value.limitKeys.forEach((key) => {
      limitData[key] = '';
    });
  };

  // ----------------------------------------------------------  报警信息 ---------------------------------------
  const warningMessage = ref('');

  const getWarningMessage = async () => {
    try {
      const params = { prodLine: activeTab.value };
      const res = await rateApi.getWarningMessage(params);
      if (res.data) {
        warningMessage.value = res.data.data;
      }
    } catch (error) {
      const errorInfo = {
        message: '获取提示信息失败',
        error: error instanceof Error ? error.message : String(error),
        timestamp: new Date().toISOString(),
      };
      console.error('API Error:', errorInfo);
      errList.value.push(errorInfo.message);
    }
  };

  // 每到整点刷新一次提示信息
  let warningAlignTimeout: number | undefined;
  let warningHourlyTimer: number | undefined;

  const scheduleHourlyWarningRefresh = () => {
    // 先清理已有的
    if (warningAlignTimeout) {
      clearTimeout(warningAlignTimeout);
      warningAlignTimeout = undefined;
    }
    if (warningHourlyTimer) {
      clearInterval(warningHourlyTimer);
      warningHourlyTimer = undefined;
    }

    const now = new Date();
    const nextTop = new Date(now);
    nextTop.setMinutes(0, 0, 0);
    nextTop.setHours(nextTop.getHours() + 1);
    const delay = nextTop.getTime() - now.getTime();

    warningAlignTimeout = window.setTimeout(() => {
      // 到整点立即刷新一次
      getWarningMessage();
      // 之后每小时刷新
      warningHourlyTimer = window.setInterval(
        () => {
          getWarningMessage();
        },
        60 * 60 * 1000
      );
    }, delay);
  };
</script>
<style lang="scss" scoped>
  .container {
    width: 99%;
    background: url(/@/assets/images/home/body-bg.jpg) no-repeat;
  }

  .el-dropdown-link {
    cursor: pointer;
    color: var(--el-color-primary);
    display: flex;
    align-items: center;
    font-size: 16px;
  }

  .header-search-form {
    color: #fff;
    width: 100%;
    height: auto;
    display: flex;
    flex-direction: column;
    gap: 1rem;
    padding: 12px;
    margin: 0.5% auto;

    .form-group {
      display: flex;
      gap: 1rem;
      justify-content: flex-start;
    }

    :deep(.el-form-item__label) {
      color: #fff !important;
    }
  }

  .card-header {
    display: flex;
    text-align: center;
    background-image: -webkit-linear-gradient(left, #0072ff, #00eaff, #01aaff);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    font-size: 2vh;
    font-weight: bolder;
  }

  .coild-list {
    :deep(.el-card) {
      width: 100%;
      height: 100%;
      color: #fff;
      border: none;
      background-color: transparent !important;
    }

    :deep(.el-table) {
      background-color: transparent !important;
      --el-table-border: none;
      --el-table-row-hover-bg-color: unset;
      color: white;
    }

    :deep(.el-table th),
    :deep(.el-table tr),
    :deep(.el-table td) {
      background-color: transparent;
    }

    :deep(.el-table__row:nth-child(odd)) {
      background-color: #223671;
    }

    :deep(.el-table__inner-wrapper::before) {
      left: 0;
      bottom: 0;
      width: 100%;
      height: 0;
    }
  }

  .space {
    margin: 0 1rem;
  }

  // 图表区域
  .charts-container {
    padding: 12px;
    background: transparent;
    height: 80vh;
    overflow: auto;
  }

  .charts-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(2, 1fr);
    padding: 12px;
    height: 100%;
  }

  .chart-item {
    height: 35vh;
    width: 52vh;
    margin: 0 1vw 1vh 0; //上、右、下、左
    background: transparent;
    border: 1px solid #0072ff;
    border-radius: 8px;
    padding: 15px;
    transition: all 0.3s ease;

    &:hover {
      border-color: #00eaff;
      box-shadow: 0 0 20px rgba(0, 234, 255, 0.3);
    }

    // .chart-container {
    //   width: 100%;
    //   height: 100%;
    //   background: transparent;
    // }
  }

  .time-period-picker :deep(.el-input__wrapper) {
    background-color: transparent !important;
  }

  .time-period-picker :deep(.el-input__inner) {
    color: #fff;
  }

  .time-period-picker :deep(.el-input__wrapper.is-focus) {
    box-shadow: 0 0 0 0.06rem rgba(255, 255, 255, 0.9) inset;
  }

  .time-period-picker :deep(.el-input__prefix) {
    color: #fff;
  }

  .filterInput :deep(.el-input__inner) {
    color: #fff;
  }

  .select :deep(.el-select__inner) {
    color: #fff;
  }

  .select :deep(.el-select__selected-item) {
    color: #fff;
  }

  :deep(.el-input__wrapper) {
    background: linear-gradient(90deg, #0b3571, rgba(11, 53, 113, 0) 100%);
    box-shadow: 0 0 0 0 var(--el-input-border-color, var(--el-border-color)) inset;
  }

  :deep(.el-select__wrapper) {
    background: linear-gradient(90deg, #0b3571, rgba(11, 53, 113, 0) 100%);
    box-shadow: 0 0 0 0 var(--el-input-border-color, var(--el-border-color)) inset;
  }

  :deep(.el-select:hover:not(.el-select--disabled) .el-input__wrapper) {
    box-shadow: 0 0 0 0 var(--el-select-input-focus-border-color) inset !important;
  }

  :deep(.el-select .el-input.is-focus .el-input__wrapper) {
    box-shadow: 0 0 0 0 var(--el-select-input-focus-border-color) inset !important;
  }

  :deep(.el-select:hover:not(.el-select--disabled) .el-input__wrapper) {
    background: #0b3571;
  }

  :deep(.el-select .el-input__wrapper) {
    background: #0b3571;
  }

  .header-search-form :deep(.el-input__inner) {
    color: #fff;
  }
</style>
